﻿namespace In66.Net.Share.Extensions
{
    public static class HostBuilderExtensions
    {
        public static IHost ChangeThreadPool(this IHost host)
        {
            var poolOptions = host.Services.GetService(typeof(IOptions<ThreadPoolConfig>)) as IOptions<ThreadPoolConfig>;
            if (poolOptions is not null)
            {
                ChangeThreadPoolConfig(host, poolOptions);
            }

            return host;
        }

        public static IHost ChangeThreadPoolConfig(this IHost host, IOptions<ThreadPoolConfig> poolOptions)
        {
            if (host.Services.GetService(typeof(ILogger<IHost>)) is not ILogger<IHost> logger)
            {
                throw new NullReferenceException(nameof(logger));
            }

            var poolSetting = poolOptions.Value;
            ThreadPool.SetMinThreads(poolSetting.MinThreads, poolSetting.MinCompletionPortThreads);
            ThreadPool.SetMaxThreads(poolSetting.MaxThreads, poolSetting.MaxCompletionPortThreads);
            ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
            ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
            logger.LogInformation("Setting MinThreads={0},MinCompletionPortThreads={1}", workerThreads, completionPortThreads);
            logger.LogInformation("Setting MaxThreads={0},MaxCompletionPortThreads={1}", maxWorkerThreads, maxCompletionPortThreads);
            return host;
        }

        public static IHost ChangeThreadPoolConfig(this IHost host, IOptionsMonitor<ThreadPoolConfig> poolOptions)
        {
            if (host.Services.GetService(typeof(ILogger<IHost>)) is not ILogger<IHost> logger)
            {
                throw new NullReferenceException(nameof(logger));
            }

            poolOptions.OnChange(poolSetting =>
            {
                ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
                ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
                logger.LogInformation("before MinThreads={0},MinCompletionPortThreads={1}", workerThreads, completionPortThreads);
                logger.LogInformation("before MaxThreads={0},MaxCompletionPortThreads={1}", maxWorkerThreads, maxCompletionPortThreads);

                ThreadPool.SetMinThreads(poolSetting.MinThreads, poolSetting.MinCompletionPortThreads);
                ThreadPool.SetMaxThreads(poolSetting.MaxThreads, poolSetting.MaxCompletionPortThreads);

                ThreadPool.GetMinThreads(out int changedWorkerThreads, out int changedCompletionPortThreads);
                ThreadPool.GetMaxThreads(out int changedMaxWorkerThreads, out int changedsMaxCompletionPortThreads);
                logger.LogInformation("changed MinThreads={0},MinCompletionPortThreads={1}", changedWorkerThreads, changedCompletionPortThreads);
                logger.LogInformation("changed MaxThreads={0},MaxCompletionPortThreads={1}", changedMaxWorkerThreads, changedsMaxCompletionPortThreads);
            });

            var poolSetting = poolOptions.CurrentValue;
            ThreadPool.SetMinThreads(poolSetting.MinThreads, poolSetting.MinCompletionPortThreads);
            ThreadPool.SetMaxThreads(poolSetting.MaxThreads, poolSetting.MaxCompletionPortThreads);

            ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
            ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
            logger.LogInformation("Setting MinThreads={0},MinCompletionPortThreads={1}", workerThreads, completionPortThreads);
            logger.LogInformation("Setting MaxThreads={0},MaxCompletionPortThreads={1}", maxWorkerThreads, maxCompletionPortThreads);
            return host;
        }

        /// <summary>
        /// register to (consul/nacos/clusterip...)
        /// </summary>
        public static IHost UseRegistrationCenter(this IHost host)
        {
            var configuration = host.Services.GetService<IConfiguration>();
            var serviceInfo = host.Services.GetService<IServiceInfo>();
            var registeredType = configuration?.GetRegisteredType().ToLower();
            switch (registeredType)
            {
                case RegisteredTypeConsts.Consul:
                    host.RegisterToConsul(serviceInfo?.Id);
                    break;
                case RegisteredTypeConsts.Nacos:
                    // TODO
                    //app.RegisterToNacos(serviceInfo.Id);
                    break;
                default:
                    break;
            }
            return host;
        }
    }
}
